package com.vhall.component.plugin.common.aspect;

import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.vhall.component.framework.common.utils.HttpServletUtils;
import com.vhall.component.plugin.common.filter.ContentCachingRequestWrapper;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.plugin.common.utils.algorithm.PaasCallbackMd5SignValidator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * paas 回调签名验证切面
 *
 * @author weifeng.yu
 * @date 2021/12/14
 */
@Slf4j
@Aspect
@Component
public class PaasCallbackSignAuthAspect {


    @Value("${paas.apps.lite.appSecret}")
    public String appSecret;

    @Pointcut("@annotation(com.vhall.component.plugin.common.annotation.PaasCallbackSignAuth)||"
            + " @within(com.vhall.component.plugin.common.annotation.PaasCallbackSignAuth)")
    public void pointCut() {
        // Do nothing
    }

    @SuppressWarnings("unchecked")
    @Around("pointCut()")
    public Object checkSign(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Assert.notNull(servletRequestAttributes, "请求参数异常");
        HttpServletRequest request = servletRequestAttributes.getRequest();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        Object[] args = joinPoint.getArgs();
        Map<String, Object> parameterMap = new HashMap<>(16);
        if (HttpServletUtils.isJsonRequest(request)) {
            String parameter = IOUtils.toString(((ContentCachingRequestWrapper) request).getBody(), request.getCharacterEncoding());
            parameterMap = JsonUtil.string2Map(parameter);
        } else {
            Map<String, String> paramMap = ServletUtil.getParamMap(request);
            parameterMap.putAll(paramMap);
        }
        log.info("PaaS callback_checkSign, request param={}", JSON.toJSONString(parameterMap));
        try {
            String signatureKey = "signature";
            Assert.notNull(response, "无法处理回调，FAIL");
            if (!parameterMap.containsKey(signatureKey)) {
                response.getWriter().write("fail");
                return null;
            }
            String signature = parameterMap.get(signatureKey).toString();
            String jsonString = JSON.toJSONString(parameterMap);
            parameterMap.remove(signatureKey);
            if (!PaasCallbackMd5SignValidator.verify(parameterMap, appSecret, signature)) {
                log.error("PaasCallback接口验签失败，接口uri：{}, parameterMap:{}", request.getRequestURI(), jsonString);
                response.getWriter().write("fail");
                return null;
            }
            return joinPoint.proceed(args);
        } catch (Throwable e) {
            log.error("", e);
            throw e;
        }
    }
}
